package io.gitee.baicaixiaozhan.configure;

import com.fasterxml.jackson.databind.AnnotationIntrospector;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import io.gitee.baicaixiaozhan.httpmessageconverter.gson.DesensitizeTypeAdapterFactory;
import io.gitee.baicaixiaozhan.httpmessageconverter.jackson.DesensitizeNopAnnotationIntrospector;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Configuration;

/**
 * DESC:
 *
 * @author baicaixiaozhan
 * @since v1.0.0
 */
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter({JacksonAutoConfiguration.class, GsonAutoConfiguration.class})
public class HttpMessageConverterAutoConfiguration {

    static final String PREFERRED_MAPPER_PROPERTY = "spring.mvc.converters.preferred-json-mapper";

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(ObjectMapper.class)
    @ConditionalOnBean(ObjectMapper.class)
    @ConditionalOnProperty(name = PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true)
    static class CustomJacksonWrapper implements BeanPostProcessor {

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof ObjectMapper) {
                ObjectMapper objectMapper = (ObjectMapper) bean;
                AnnotationIntrospector introspector = objectMapper.getSerializationConfig().getAnnotationIntrospector();
                AnnotationIntrospector allIntrospector = AnnotationIntrospector
                        .pair(introspector, new DesensitizeNopAnnotationIntrospector());
                objectMapper.setAnnotationIntrospector(allIntrospector);
                return objectMapper;
            }
            return bean;
        }
    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Gson.class)
    @ConditionalOnBean(Gson.class)
    @ConditionalOnProperty(name = PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = true)
    static class CustomGsonWrapper implements BeanPostProcessor {

        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (bean instanceof GsonBuilder) {
                GsonBuilder gsonBuilder = (GsonBuilder) bean;
                gsonBuilder.registerTypeAdapterFactory(new DesensitizeTypeAdapterFactory());
                return gsonBuilder;
            }
            return bean;
        }
    }
}
